//备注：拷贝代码请加上作者信息
//作者：王海涛
//邮箱：1126471088@qq.com
//版本：V1.0.0
#include "wwdg_bsp.h"
#include "stm32f4xx_rcc.h"
#include "misc.h"

/*WWDG起始计数*/
static unsigned char WHT_WWDG_Start_Counter;
/*WWDG窗口计数*/
static unsigned char WHT_WWDG_Windows_Counter;


/*WWDG 中断优先级配置*/
static void NVIC_Configuration(void)
{
	NVIC_SetPriority(WWDG_IRQn, 0);
	NVIC_EnableIRQ(WWDG_IRQn);
}
/*WWDG 喂狗*/
static void WHT_WWDG_BSP_Feed_Dog(void)
{
	WWDG_SetCounter(WHT_WWDG_Start_Counter);
}
/*WWDG 系统复位*/
static void WHT_WWDG_BSP_System_Restart(void)
{
	WWDG_SetCounter(0x40 - 1);
}


#ifdef WHT_WWDG_Count_Mode
/*WWDG 配置*/
static void WHT_WWDG_BSP_Config(const WHT_WWDG_Advance_Mode_Config_t* config)
{
	static FlagStatus Auto_Lock = RESET;
	
	if (Auto_Lock == SET)
		return;
	
	WHT_WWDG_Windows_Counter = (unsigned char)config->Window_Counter;
	WHT_WWDG_Start_Counter = (unsigned char)config->Start_Counter;
	WWDG_DeInit();
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
	WWDG_SetPrescaler(config->Prescaler);
	WWDG_SetWindowValue(0x7f);                   //close windows
	if (config->Early_Wakeup_Interrupt == ENABLE)
	{
		NVIC_Configuration();
		WWDG_ClearFlag();
		WWDG_EnableIT();
	}
	WWDG_Enable(WHT_WWDG_Start_Counter);//使能看门狗
	WWDG_SetWindowValue(WHT_WWDG_Windows_Counter);//open windows
	Auto_Lock = SET;//自锁
}
/*WWDG重置窗口值*/
static void WHT_WWDG_BSP_Reset_Windows_Counter(const WHT_WWDG_Advance_Mode_Config_t* config)
{
	WHT_WWDG_Windows_Counter = (unsigned char)config->Window_Counter;
	WWDG_SetWindowValue(0x7f);                    //close windows
	WHT_WWDG_BSP_Feed_Dog();
	WWDG_SetWindowValue(WHT_WWDG_Windows_Counter);//open windows
}
/*WWDG重置启动值*/
static void WHT_WWDG_Reset_Start_Counter(const WHT_WWDG_Advance_Mode_Config_t* config)
{
	WHT_WWDG_Start_Counter = (unsigned char)config->Start_Counter;
	WWDG_SetWindowValue(0x7f);                    //close windows
	WHT_WWDG_BSP_Feed_Dog();
	WWDG_SetCounter(WHT_WWDG_Start_Counter);
	WWDG_SetWindowValue(WHT_WWDG_Windows_Counter);//open windows
}

/*全局常量*/
const WHT_WWDG_BSP_Advance_Mode_t WHT_WWDG_BSP_Advance_Mode =
{
	.WHT_Config                = WHT_WWDG_BSP_Config,
	.WHT_Feed_Dog              = WHT_WWDG_BSP_Feed_Dog,
	.WHT_System_Restart        = WHT_WWDG_BSP_System_Restart,
	.WHT_Reset_Windows_Counter = WHT_WWDG_BSP_Reset_Windows_Counter,
	.WHT_Reset_Start_Counter   = WHT_WWDG_Reset_Start_Counter,
};
#else //时间模式
/*WWDG 配置*/
static void WHT_WWDG_BSP_Config(const WHT_WWDG_Config_t* config)
{
	static FlagStatus Auto_Lock = RESET;
	unsigned int WWDG_Prescaler;
	
	if (Auto_Lock == SET)
		return;
	
	WWDG_Prescaler = WWDG_Prescaler_8;                                                                     //default 初略设定
	//WHT_WWDG_Windows_Counter = (unsigned int)((float)(config->Window_Time_ms * 4096 * 8) / (float)config->APB1_Clk_KHz + 0.5f);//四舍五入
	WHT_WWDG_Windows_Counter = (config->Window_Time_ms << 15) / config->APB1_Clk_KHz + 1;
	WHT_WWDG_Windows_Counter = WHT_WWDG_Windows_Counter >= 0x40 ? 0x7f : (0x40 + WHT_WWDG_Windows_Counter);//设置过大则default 0x7f
	//WHT_WWDG_Start_Counter = (unsigned int)((float)(config->Start_Time_ms * 4096 * 8) / (float)config->APB1_Clk_KHz + 0.5f);
	WHT_WWDG_Start_Counter = (config->Start_Time_ms << 15) / config->APB1_Clk_KHz + 1;
	WHT_WWDG_Start_Counter = WHT_WWDG_Start_Counter >= 0x40 ? 0x7f : (0x40 + WHT_WWDG_Start_Counter);
	WWDG_DeInit();
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
	WWDG_SetPrescaler(WWDG_Prescaler);
	WWDG_SetWindowValue(0x7f);                   //close windows
	if (config->Early_Wakeup_Interrupt == ENABLE)
	{
		NVIC_Configuration();
		WWDG_ClearFlag();
		WWDG_EnableIT();
	}
	WWDG_Enable(WHT_WWDG_Start_Counter);//使能看门狗
	WWDG_SetWindowValue(WHT_WWDG_Windows_Counter);//open windows
	Auto_Lock = SET;//自锁
}
/*WWDG重置窗口时间*/
static void WHT_WWDG_BSP_Reset_Windows_Time(const WHT_WWDG_Config_t* config)
{
	WHT_WWDG_Windows_Counter = (config->Window_Time_ms << 15) / config->APB1_Clk_KHz + 1;
	WHT_WWDG_Windows_Counter = WHT_WWDG_Windows_Counter >= 0x40 ? 0x7f : (0x40 + WHT_WWDG_Windows_Counter);
	WWDG_SetWindowValue(0x7f);                    //close windows
	WHT_WWDG_BSP_Feed_Dog();
	WWDG_SetWindowValue(WHT_WWDG_Windows_Counter);//open windows
}
/*WWDG重置启动时间*/
static void WHT_WWDG_BSP_Reset_Start_Time(const WHT_WWDG_Config_t* config)
{
	WHT_WWDG_Start_Counter = (config->Start_Time_ms << 15) / config->APB1_Clk_KHz + 1;
	WHT_WWDG_Start_Counter = WHT_WWDG_Start_Counter >= 0x40 ? 0x7f : (0x40 + WHT_WWDG_Start_Counter);
	WWDG_SetWindowValue(0x7f);                    //close windows
	WHT_WWDG_BSP_Feed_Dog();
	WWDG_SetCounter(WHT_WWDG_Start_Counter);
	WWDG_SetWindowValue(WHT_WWDG_Windows_Counter);//open windows
}

/*全局常量*/
const WHT_WWDG_BSP_t WHT_WWDG_BSP =
{
	.WHT_Config             = WHT_WWDG_BSP_Config,
	.WHT_Feed_Dog           = WHT_WWDG_BSP_Feed_Dog,
	.WHT_System_Restart     = WHT_WWDG_BSP_System_Restart,
	.WHT_Reset_Windows_Time = WHT_WWDG_BSP_Reset_Windows_Time,
	.WHT_Reset_Start_Time   = WHT_WWDG_BSP_Reset_Start_Time,
};
#endif


/*WWDG中断服务程序*/
void WWDG_IRQHandler(void)
{
	/*先清除标志位，因为标志位清除后需要很少时间才真正的被清理掉*/
	WWDG_ClearFlag();
	WHT_WWDG_BSP_Feed_Dog();
	/*下面函数注释掉，当发现中断重复进入导致系统重启，建议开启下面这个函数*/
	//while (WWDG_GetFlagStatus() == SET);//WWDG内部清除标志位慢，这里同步等待一下, 防止中断重入导致多次喂狗系统重启
}
